#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>


#define LOG( fmt, ... ) fprintf( stderr, fmt "\n", ##__VA_ARGS__ )
#define LOG_DEBUG( fmt, ... )  LOG( "[DEBUG] "fmt, ##__VA_ARGS__ )
#define LOG_ERR( fmt, ... )  LOG( "[ERR] "fmt, ##__VA_ARGS__ )

int main( int argc, char *argv[] )
{
	if( argc < 3 ) {
		LOG_ERR( "%s src_path dest_path", argv[0] );
		exit( EXIT_FAILURE );
	}

	const char *src_path = argv[1];
	const char *dest_path = argv[2];

	int src_fd = open( src_path, O_RDONLY );
	if( src_fd < 0 ) {
		LOG_ERR( "open %s failed, errno %d", src_path, errno );
		exit( EXIT_FAILURE );
	}
	int dest_fd = open( dest_path, O_RDWR | O_CREAT );
	if( dest_fd < 0 ) {
		LOG_ERR( "open %s failed, errno %d", dest_path, errno );
		exit( EXIT_FAILURE );
	}

	struct stat st;
	if( fstat( src_fd, &st ) != 0 ) {
		LOG_ERR( "stat %s failed, errno %d", src_path, errno );
		exit( EXIT_FAILURE );
	}
	LOG_DEBUG( "size %ld", st.st_size );

	if( ftruncate( dest_fd, st.st_size ) != 0 ) {
		LOG_ERR( "ftruncate failed, errno %d", errno );
		exit( EXIT_FAILURE );
	}

	void *src_addr = mmap( NULL, st.st_size, PROT_READ, MAP_SHARED, src_fd, 0 );
	if( MAP_FAILED == src_addr ) {
		LOG_ERR( "mmap failed, errno %d", errno );
		exit( EXIT_FAILURE );
	}
	void *dest_addr = mmap( NULL, st.st_size, PROT_WRITE, MAP_SHARED, dest_fd, 0 );
	if( MAP_FAILED == dest_addr ) {
		LOG_ERR( "mmap failed, errno %d", errno );
		exit( EXIT_FAILURE );
	}

	memcpy( dest_addr, src_addr, st.st_size );
}

